OpenCode Telegram Bot 系统梳理
基于 grinev/opencode-telegram-bot、OpenCode SDK、OpenCode Server 官方文档整理。
版本:v0.22 (npm@grinev/opencode-telegram-bot)
1. 概述
OpenCode Telegram Bot 是一个通过 Telegram 操控本地 OpenCode Server 的桥接程序。 由 Ruslan Grinev 开发,MIT 协议开源,基于 Node.js (TypeScript) + grammY 框架。
核心思路:把 Telegram 变成你手机上的 OpenCode 终端窗口。
- 零开放端口 — Bot 主动长轮询 Telegram API,不以 webhook 方式暴露服务
- 本地代理 — 运行在 OpenCode Server 同一台机器上,通过 HTTP + SSE 通信
- 单用户白名单 — 仅
TELEGRAM_ALLOWED_USER_ID匹配的用户可操控 - 支持 macOS / Windows / Linux,提供 npm 全局安装、Docker、systemd 多种运行方式
2. 系统架构
2.1 行为图(系统"做什么")
用例图
系统角色只有一人(机器所有者),通过 Telegram Bot 对本地 OpenCode 进行远程操控。可选接入 STT/TTS/文档提取 API。
// Demo: 用户发一条消息给 Bot 的命令映射
// 文本消息(非命令) → 作为 prompt 发给 OpenCode
// /status → 查服务器/项目/会话/模型信息
// /new → 创建新会话
// /abort → 终止当前任务
// /sessions → 浏览并切换会话
// /projects → 切换项目
// /task → 创建定时任务
// 语音消息 → STT 转录 → 作为 prompt 发送
活动图
消息从 Telegram 到达后的处理全流程。
时序图
一次完整的"用户发送 prompt → LLM 回复 → 用户看到结果"交互链路。
状态机图
Bot 自身生命周期状态及其与 OpenCode Server SSE 事件流的连接状态管理。
2.2 结构图(系统"由什么组成")
组件图
部署图
类图
3. 关键架构决策
| 决策 | 背景 | 效果 |
|---|---|---|
| 长轮询 getUpdates 而非 webhook | 运行在本地机器 / 无公网 IP 的云服务器 | 零配置、无入站端口、适合所有网络环境 |
| SSE 而非 WebSocket | opencode serve 原生提供 /global/event SSE 端点 |
零额外握手开销,天然支持重连 |
| 单项目单活跃 session | Telegram 约 1 msg/s 限速,多 session 并发容易竞态 | 行为可预测,交互式 Q&A 不会失控 |
| setImmediate 调度事件 | SSE 事件洪流可能阻塞 Telegram getUpdates 长轮询 | Bot 不会被判离线,始终保持消息接收 |
| 编辑消息实现流式输出 | 逐条发送会导致刷屏,违反 Telegram UX 规范 | 同一条消息内持续更新(按 1s 节流) |
| 代码块作为文件附件 (≤100KB) | Telegram 单条消息 4096 字符限制 | 代码不受截断,支持语法高亮 |
| 30s 空闲超时主动断流 | keepalive 老化可能导致连接假死 | 始终保持健康连接,指数退避重连 |
| 交互式 flow 互斥锁 | 多个交互(权限询问 + 命令菜单 + 会话切换)并发会破坏上下文 | 同一时刻只有一个交互流活跃,避免误操作 |
| HTTP Basic Auth 保护 opencode serve | 虽然绑定 127.0.0.1,但同主机多进程仍需隔离 | 可选 OPENCODE_SERVER_PASSWORD 即启动密码验证 |
4. 速查手册
4.1 Bot 命令一览
| 命令 | 功能 |
|---|---|
/status | 服务器健康状态、当前项目、会话、模型信息 |
/new | 创建新会话 |
/abort | 终止当前任务(等效 ESC) |
/detach | 从当前会话分离,不停止任务 |
/sessions | 浏览并切换最近会话 |
/messages | 浏览用户消息,支持 Revert(回退)和 Fork(分支) |
/projects | 切换 OpenCode 项目 |
/worktree | 切换 git worktree(当前 repo) |
/open | 浏览目录以添加项目 |
/ls | 交互式文件浏览器(当前项目目录) |
/settings | 修改运行时设置 |
/rename | 重命名当前会话 |
/commands | 浏览并执行自定义命令和内置命令(init、review 等) |
/skills | 浏览并执行 OpenCode skills |
/mcps | 浏览并切换 MCP 服务器 |
/task | 创建定时任务 |
/tasklist | 浏览并删除定时任务 |
/opencode_start | 启动本地 OpenCode server |
/opencode_stop | 停止本地 OpenCode server |
/help | 显示可用命令 |
4.2 运行时设置 (/settings)
| 设置项 | 说明 | 可选值 |
|---|---|---|
| Compact output mode | 紧凑输出模式 | on/off |
| Thinking content display | 是否显示模型推理过程 | on/off |
| Assistant run footer | 显示助手运行页脚 | on/off |
| Diff file attachments | 发送 diff 文件作为附件 | on/off |
| Response streaming mode | 回复流式输出模式 | edit / draft(实验性) |
| Audio replies | TTS 语音回复模式(需 TTS 配置) | off / all / auto |
4.3 快速启动 (npm)
# 1. 在 @BotFather 创建 Bot,拿到 token
# 2. 给 @userinfobot 发消息,拿到你的 user ID
# 3. 启动 opencode serve
opencode serve --port 4096 &
# 4. 启动 bot(首次运行交互式向导)
npx @grinev/opencode-telegram-bot@latest
# 或全局安装
npm install -g @grinev/opencode-telegram-bot
opencode-telegram start
# 后台守护模式
opencode-telegram start --daemon
opencode-telegram status
opencode-telegram stop
4.4 跟踪已有会话
# 方式一:单个 TUI,固定端口
opencode --port 4096
# 方式二:多个 TUI,共享后端
opencode serve --port 4096 # 终端1:启动后端
opencode attach http://127.0.0.1:4096 # 终端2+:attach
5. 环境变量速查
| 变量 | 必填 | 默认值 | 说明 |
|---|---|---|---|
TELEGRAM_BOT_TOKEN | 是 | — | @BotFather 获取的 token |
TELEGRAM_ALLOWED_USER_ID | 是 | — | 你的数字 Telegram User ID |
OPENCODE_API_URL | 否 | http://localhost:4096 | OpenCode Server 地址 |
OPENCODE_MODEL_PROVIDER | 是 | opencode | 默认模型提供商 |
OPENCODE_MODEL_ID | 是 | big-pickle | 默认模型 ID |
BOT_LOCALE | 否 | en | 界面语言 (en/ar/de/es/fr/ru/zh) |
TELEGRAM_PROXY_URL | 否 | — | SOCKS5/HTTP 代理(绕过防火墙) |
TELEGRAM_API_ROOT | 否 | https://api.telegram.org | 自建反向代理(企业网络) |
OPENCODE_AUTO_RESTART_ENABLED | 否 | false | health check 失败时自动重启 serve |
OPENCODE_SERVER_USERNAME | 否 | opencode | serve 认证用户名 |
OPENCODE_SERVER_PASSWORD | 否 | — | serve 认证密码 |
STT_API_URL / STT_API_KEY | 否 | — | 语音转文字(Whisper 兼容 API) |
TTS_PROVIDER / TTS_API_URL | 否 | — | 文字转语音(OpenAI / ElevenLabs / Google) |
DOC_EXTRACTOR_URL | 否 | — | 文档提取 API(PDF/DOCX/PPTX) |
TASK_LIMIT | 否 | 10 | 最大定时任务数 |
SCHEDULED_TASK_EXECUTION_TIMEOUT_MINUTES | 否 | 120 | 单次定时任务超时(分钟) |
LOG_LEVEL | 否 | info | 日志级别 (debug/info/warn/error) |
6. 部署方案
6.1 systemd 自启(推荐生产环境)
将 opencode serve 和 bot 各做成一个 systemd 服务,开机自启 + 崩溃自动重启:
# ---- /etc/systemd/system/opencode-serve.service ----
[Unit]
Description=OpenCode Server (serve :4096)
After=network-online.target
PartOf=opencode-telegram-bot.service
Wants=opencode-telegram-bot.service
[Service]
Type=simple
Environment=HOME=/root
ExecStart=/root/.opencode/bin/opencode serve --port 4096
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
# ---- /etc/systemd/system/opencode-telegram-bot.service ----
[Unit]
Description=OpenCode Telegram Bot
After=network-online.target opencode-serve.service
Requires=opencode-serve.service
BindsTo=opencode-serve.service
[Service]
Type=simple
Environment=HOME=/root
ExecStart=/usr/bin/opencode-telegram start
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
# 启用
systemctl daemon-reload
systemctl enable --now opencode-serve.service opencode-telegram-bot.service
# 日常操作
systemctl restart opencode-serve # bot 自动联动
systemctl status opencode-telegram-bot
journalctl -u opencode-telegram-bot -f
6.2 Docker 多栈隔离(本地 Mac / 多项目)
# Personal Stack (个人项目)
docker run -d --name bot-personal \
-e TELEGRAM_BOT_TOKEN=xxx \
-e TELEGRAM_ALLOWED_USER_ID=123 \
-v ~/projects/personal:/workspace \
@grinev/opencode-telegram-bot
# Work Stack (公司项目)
docker run -d --name bot-work \
-e TELEGRAM_BOT_TOKEN=yyy \
-e TELEGRAM_ALLOWED_USER_ID=123 \
-v ~/projects/work:/workspace \
@grinev/opencode-telegram-bot
每个 Docker stack 包含:一个 bot 容器 + 一个 opencode serve 容器 + 一个工作目录 volume,通过内部 bridge 网络通信,与外界仅通过 Telegram API 交互。
6.3 注意事项
- serve 和 bot 的 systemd 依赖不要写双向 — serve 用
PartOf=bot.service+Wants=bot.service,bot 用Requires=serve.service+BindsTo=serve.service,单边绑定避免 stop 传播死锁 - 国内环境需代理 — 用 proxychains-ng 截获 TCP,排除 127.0.0.1:4096 直连 serve
- .env 文件确保 600 权限 — 含 bot token,勿提交 git
- 如机器有休眠行为 — 需额外禁用 (GNOME:
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout 0)